<?php

namespace App\Http\Controllers\PartnerApi;

use App\Enums\AssetStatus;
use App\Enums\ExchangeChannel;
use App\Enums\TransferSource;
use App\Enums\TransferStatus;
use App\Http\Controllers\Controller;
use App\Jobs\TransferJob;
use App\Models\Asset;
use App\Models\FrontendUser;
use App\Models\ProductConfig;
use App\Models\TransferRecord;
use Illuminate\Support\Arr;

class DingblockController extends Controller
{
    private $dingblockPubKey = '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzMVET2BA/KRJXA/FqBYk
K2iT5pl39rfw3ZdeSZnaqeS3rZWiVqcWCeEj9CqHenB5TtgPhpyBmx24FVSmJ+zt
5R78Q10E7mJSPEeSQO7QUDABNeS18XomZx6JKfIe5k7J/Cgbr9wqQ5qc3sEReYz0
D2e1mmtWUQryHWhMgj75w85CcXpuSoCo9Zej+Mz9+puIQz0ZvFjVDabvJwMCeNR5
0F8xcvwfUvnmi9qw4xurbsToujoE9ukwkVQC7Na9979UE1KW2QRNhx8j1ze715qA
kZtJVxOo1WHLH9Q7TIbZRc3qejPCrjv0vRQWqGqXq265tob0CE96tJFGXeqojsWn
qQIDAQAB
-----END PUBLIC KEY-----';
    // 一级平台RSA私钥
    private $userPrivateKey = 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDJCbtgXezsd37WYTSfeMBKYT4jvqQ8H9Z7fO97ugsbqL/SJiGiolkosVZ4+STsVTJIqNjpXYXmwcbbSC1XmztK+RYmqD9bqUSccA6HYpycF2Jq9rohgnHWDnTK1Dy3Y2I2bJSj5tA13Rp9yt306BSRQGOiej30izKBgZseuvr1DmLpu/oPiTJC4N1ZWjMFj3j2dckD1OqW8TeXK0lpn/ZG9oP/1Jh5/K0Sl2ATzJLbYaNzQGWpiQDDmQXP7HShGy2cL3HkerFiEPwxNED49WY5g1tgDKkzLwMMmOYzBcivKjc8K10mzGm335Ixz/+3BCTn1GMth+Nc5kHWpykyxeC7AgMBAAECggEAO8GAyKwieEcslFxgX+Zsga9V4RoRhy2PezUvmf86vgXyvmxHIyhOiCHuKhckOns4bxCBKRx7aJPAn/1cPOYPQcG4K9Vmv8AYfMdyChvtoRfyUQj1WnCDlbTGUmOziG8qCjNMG0vIJ7qI3Usnnlw9gM86zli3gbC+WnBDw2agoaYV16IxiuArinrs50zHjCEFU8+4uv4rtvDe1nvRZFe0STXOMTplHkEMdNcLHi9VPUScxtBB8mij4wVe3CJydGVtd6HKFkL4aRbRhUzQ4Sv2UCMz6BKWEH1fr+Iqifd1HTXmJIz9tU5yFO8sPlROcz1g70LYeoo8lDKr6ZpGqTOIQQKBgQDz/6ACFrsA5S6qBsn4INA2hLzdwpBMb54Mo4cxUBO0lQqpKwcrIjtyfxZVBjX0OYgsiw9JdPsClZRYNP/AIgJ+Ftj/3AlPHOR8a2Of3zwQ1YWjdckY7qIy36UDlFyr4jJWflTNBVDDMQx6Wv+lPjAKKyemVcTgvPPa4gzZnsUorwKBgQDS7Shb4yAc1IRe0YriJiH18t1yGwOOob6/nnKu2+zds3iH/7BumIqGFvrktz3XjdmK8UW00vTw4oQTP9yjX/p84pnQO129ycHcBplaX0I5XwenJ+RWTH65FRAiYagtqnHkzz/FnRC84CvqWWHmhAcKEKBwwrMKorCxOopTvN7ztQKBgQCjOByRSSNPNgBBPMlecpTV43Vz4vMkLoZLbhjBpA+KfSjkgSQKdpvNu7X0qnLtLI8rPNq9CMPgtq7FUq7Cl/2S2zXN8iNICMvPbwb1qx9DI5KCBgi/5OIbpf98pYJYeLezpE6V1zhvWiA+uSDKKQ95veSIIFfS/pMhmJV//fVlgQKBgEs/N+qv+EDQv/hjoLxVBkCLx9xxLq+vnDEYAanH45Sj9hfua67I1IJJqG/3vyQrArTCpi+AIsncxWlomvndv6rV3DGhPCv80iAAaq0G1sVI1Z4YaSkwWPUGQp9BX5ILAF60YPfKtLHs9z2/bWGjMC+zBsmza9QbfhV74OVGt/MRAoGAL1KcT3eJ3RJpVtMU8A0SE0bNX3eYfL2WHX/GpPprVHY2NakxkwxnVJJb9SVsYV+mo8Nq18H2U6/7yoJ5cI4zt3K5tTRN5ojSKerrm/4SjOhsm9BpPMGxUx+6IRak85pHuuCWiE4y1WlNsWSJHD/Ma2egB8Ac2bwxM+kD06/0X3c=';

    /**
     * 验证用户手机号.
     */
    public function phone()
    {
        $param = $this->parseBizData(request()->bizData);

        if (empty($param['phoneNumber'])) {
            return $this->failResponse('请输入手机号');
        }

        $user = FrontendUser::where('agent_id', request()->agent_id)->where('mobile', $param['phoneNumber'])->first();

        if (!empty($user)) {
            return $this->successResponse();
        }

        return $this->failResponse('该手机号没有注册信息');
    }

    /**
     * 转赠.
     */
    public function apply()
    {
        $bizData = $this->parseBizData(request()->bizData);

        if (empty($bizData['buyerPhoneNumber'])) {
            return $this->failResponseWithCode(-1, '请输入接收人手机号');
        }
        if (empty($bizData['sellerPhoneNumber'])) {
            return $this->failResponseWithCode(-1, '请输入转让人手机号');
        }
        if (empty($bizData['collectionId'])) {
            return $this->failResponseWithCode(-1, '请输入藏品系列id');
        }
        if (empty($bizData['uniqueId'])) {
            return $this->failResponseWithCode(-1, '请输入藏品唯一id');
        }
        if (empty($bizData['orderId'])) {
            return $this->failResponseWithCode(-1, '请输入orderId');
        }
        $orderId = $bizData['orderId'];
        $existRecord = TransferRecord::query()
            ->where('source', TransferSource::DING_BLOCK)
            ->where('transfer_sn', $orderId)
            ->first();
        if ($existRecord) {
            return $this->failResponseWithCode(-1, '重复的订单号');
        }
        $buyer = FrontendUser::where('agent_id', request()->agent_id)->where('mobile', $bizData['buyerPhoneNumber'])->first();
        if (!$buyer) {
            return $this->failResponseWithCode(-1, '无效的购买方账号');
        }
        $seller = FrontendUser::where('agent_id', request()->agent_id)->where('mobile', $bizData['sellerPhoneNumber'])->first();
        if (!$seller) {
            return $this->failResponseWithCode(-1, '无效的卖方账号');
        }

        $asset = Asset::query()
            ->where('contract_address', $bizData['collectionId'])
            ->where('token_id', $bizData['uniqueId'])
            ->where('asset_status', AssetStatus::HOLD)
            ->first();
        if (!$asset) {
            return $this->failResponseWithCode(-1, '资产未找到');
        }
        if ($asset->user_id != $seller->id) {
            return $this->failResponseWithCode(-1, '资产不属于卖方');
        }
        $record = new TransferRecord();
        $record->agent_id = request()->agent_id;
        $record->asset_id = $asset->id;
        $record->to_user_id = $buyer->id;
        $record->source = TransferSource::DING_BLOCK;
        $record->transfer_sn = $orderId;
        $record->source_params = json_encode($bizData);
        $record->save();
        TransferJob::dispatch($record);

        return $this->wrapResponse(['resultCode' => '1', 'outOrderId' => $this->getOutOrderId($orderId)]);
    }

    /**
     * 转赠验证结果.
     *
     * @return array
     */
    public function applyConfirm()
    {
        $bizData = $this->parseBizData(request()->bizData);
        if (empty($bizData['orderId'])) {
            return $this->failResponseWithCode(-1, '请输入orderId');
        }
        if (!empty($bizData['outOrderId']) && $this->getOutOrderId($bizData['orderId']) != $bizData['outOrderId']) {
            return $this->failResponseWithCode(-1, '无效的outOrderId');
        }

        /** @var TransferRecord $record */
        $record = TransferRecord::query()->where('source', TransferSource::DING_BLOCK)
            ->where('agent_id', request()->agent_id)
            ->where('transfer_sn', $bizData['orderId'])
            ->first();

        if (!$record) {
            return $this->failResponseWithCode(-1, '未找到对应转增记录');
        }

        if ($record->status->is(TransferStatus::SUCCESS)) {
            return $this->wrapResponse(['resultCode' => '1']);
        }
        if ($record->status->is(TransferStatus::WAITING)) {
            return $this->failResponseWithCode(-1, '等待转账');
        }

        return $this->failResponseWithCode(-1, '转账失败');
    }

    /**
     * 获取用户藏品列表.
     */
    public function getProducts()
    {
        $param = $this->parseBizData(request()->bizData);

        $page = $param['pageNum'] ?? 1;
        $limit = 20;
        $keywords = $param['keyword'] ?? '';

        if (empty($param['phoneNumber'])) {
            return $this->failResponse('请输入手机号');
        }
        $user = FrontendUser::where('agent_id', request()->agent_id)->where('mobile', $param['phoneNumber'])->first();
        if (empty($user)) {
            return $this->failResponse('用户未注册');
        }
        $query = Asset::where('user_id', $user->id)
            ->where('asset_status', AssetStatus::HOLD);

        //查询上架到盯链交易所的商品
        $onlineProducts = ProductConfig::query()
            ->where('config_key', ProductConfig::EXCHANGE_CHANNEL)
            ->where('config_value', ExchangeChannel::DING_BLOCK)
            ->distinct()
            ->pluck('contract_address')->toArray();

        $assetProducts = $query
            ->leftJoin('products', 'assets.contract_address', '=', 'products.contract_address')
            ->when(!empty($keywords), function ($q) use ($keywords) {
                return $q->where('products.name', 'like', '%' . $keywords . '%');
            })
            ->select('assets.*', 'products.id as p_id', 'products.agent_id', 'products.name', 'products.logo_url', 'products.contract_address')
            ->offset($limit * ($page - 1))
            ->limit($limit)
            ->orderByDesc('id')
            ->where('agent_id', request()->agent_id)
            ->get();
        $list = [];
        foreach ($assetProducts as $item) {
            $list[] = [
                'uniqueId' => $item->token_id,
                'collectionId' => $item->contract_address,
                'collectionNo' => $item->p_id,
                'collectionName' => $item->name,
                'collectionImageUrl' => $item->logo_url,
                'isTradable' => in_array($item->contract_address, $onlineProducts),
            ];
        }

        return $this->wrapResponse(['collectionList' => $list]);
    }

    /**
     * 验证单个藏品是否可转增.
     */
    public function verifyProduct()
    {
        $bizData = $this->parseBizData(request()->bizData);
        if (empty($bizData['phoneNumber'])) {
            return $this->failResponse('请输入手机号');
        }
        $user = FrontendUser::where('agent_id', request()->agent_id)->where('mobile', $bizData['phoneNumber'])->first();
        if (empty($user)) {
            return $this->failResponse('用户未注册');
        }
        if (empty($bizData['collectionId'])) {
            return $this->failResponse('请输入藏品系列id');
        }
        $collectionId = $bizData['collectionId'];
        if (empty($bizData['uniqueId'])) {
            return $this->failResponse('请输入藏品唯一id');
        }

        $asset = Asset::where('contract_address', $collectionId)
            ->where('user_id', $user->id)->where('token_id', $bizData['uniqueId'])
            ->where('asset_status', AssetStatus::HOLD)
            ->first();

        if (empty($asset)) {
            return $this->failResponse('未找到该藏品');
        }

        $productConfigs = ProductConfig::query()->whereIn('config_key', [ProductConfig::IS_LOCKED, ProductConfig::EXCHANGE_CHANNEL])
            ->where('contract_address', $asset->contract_address)
            ->get()->mapWithKeys(function (ProductConfig $config) {
                return [$config->config_key => $config->config_value];
            });
        if (!Arr::get($productConfigs, ProductConfig::IS_LOCKED, false)) {
            return $this->failResponse('发行平台配置错误: 商品未锁定');
        }
        if (ExchangeChannel::DING_BLOCK != Arr::get($productConfigs, ProductConfig::EXCHANGE_CHANNEL)) {
            return $this->failResponse('发行平台配置错误: 交易所未设置为盯链');
        }

        return $this->successResponse();
    }

    private function getOutOrderId($orderId)
    {
        return 'out_' . $orderId;
    }

    private function parseBizData($param)
    {
        return json_decode($param, true);
    }

    private function failResponse($msg)
    {
        $data = [
            'result' => false,
            'failedReason' => $msg,
        ];

        return $this->wrapResponse($data);
    }

    private function failResponseWithCode($code, $msg)
    {
        $data = [
            'resultCode' => '' . $code,
            'failedReason' => $msg,
        ];

        return $this->wrapResponse($data);
    }

    private function successResponse()
    {
        return $this->wrapResponse([
            'result' => true,
        ]);
    }

    private function wrapResponse($result)
    {
        $data = [];
        $data['code'] = 200;
        $data['msg'] = '响应成功';
        $data['nonce'] = md5(uniqid(microtime(true), true));
        $data['timestamp'] = time() * 1000;
        $data['bizData'] = json_encode($result);
        $sign = $this->sign($data);
        $data['sign'] = $sign;

        return $data;
    }

    /**
     * 加签方法.
     *
     * @param mixed $data
     */
    private function sign($data)
    {
        // 组装签名字符串
        $arr = [];
        foreach ($data as $name => $value) {
            // 如果bizData没有转成jsonstring
            if ('bizData' == $name && !is_string($value)) {
                return;
            }
            if ('sign' != $name) {
                array_push($arr, $name . '=' . $value);
            }
        }
        sort($arr);
        $signStr = join('&', $arr);

        $search = [
            '-----BEGIN RSA PRIVATE KEY-----',
            '-----END RSA PRIVATE KEY-----',
            "\n",
            "\r",
            "\r\n",
        ];
        $private_key = str_replace($search, '', $this->userPrivateKey);
        $private_key = $search[0] . PHP_EOL . wordwrap($private_key, 64, "\n", true) . PHP_EOL . $search[1];

        $res = openssl_get_privatekey($private_key);
        if ($res) {
            openssl_sign($signStr, $sign, $res, OPENSSL_ALGO_SHA256);
        } else {
            return -1;
        }

        return base64_encode($sign);
    }

    /**
     * 验签方法.
     *
     * @param mixed $req
     */
    private function verify($req)
    {
        $sign = $req->post('sign');
        // 组装签名字符串
        $arr = [];
        foreach ($req->post() as $name => $value) {
            if ('sign' != $name && 'agent_id' != $name) {
                array_push($arr, $name . '=' . $value);
            }
        }
        sort($arr);
        $signStr = join('&', $arr);

        $search = [
            '-----BEGIN PUBLIC KEY-----',
            '-----END PUBLIC KEY-----',
            "\n",
            "\r",
            "\r\n",
        ];
        //将pem格式密钥转换为openssl格式密钥
        $public_key = str_replace($search, '', $this->dingblockPubKey);
        $public_key = $search[0] . PHP_EOL . wordwrap($public_key, 64, "\n", true) . PHP_EOL . $search[1];
        $key = openssl_get_publickey($public_key);
        if (!$key) {
            return 0;
        }
        //调用openssl内置方法验签
        return (bool) openssl_verify($signStr, base64_decode($sign), $key, OPENSSL_ALGO_SHA256);
    }
}
